package com.leyantech.ecp.agenx.translator.filter.client;

import com.leyantech.ecp.agenx.common.utils.CacheUtils;
import com.leyantech.ecp.agenx.common.utils.JsonUtils;
import com.leyantech.utility.config.ConfigUtil;

import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.gson.reflect.TypeToken;
import io.vertx.core.json.JsonObject;
import lombok.extern.slf4j.Slf4j;

import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * @author eahau, {@literal <eahau@foxmail.com>}
 * @date 2022-11-15.
 */
@Slf4j
public class DuplicateMessageFilter implements ClientMessageFilter {

  static final Supplier<LoadingCache<String, Boolean>> cache = CacheUtils
      .buildCache("duplicate-message", k -> Boolean.TRUE);

  static class KeyWordMapper implements Function<JsonObject, String> {

    private final String key;

    protected KeyWordMapper(String key) {
      this.key = key;
    }

    @Override
    public String apply(JsonObject message) {
      return message.getString(key);
    }

  }

  static final Supplier<List<KeyWordMapper>> UNIQUE_KEY_MAPPERS = ConfigUtil.getDynamicConfig(
      "duplicate.message.key",
      json -> JsonUtils.fromJson(json, new TypeToken<Set<String>>() {
          })
          .stream()
          .map(KeyWordMapper::new)
          .collect(Collectors.toList()),
      Collections.singletonList(new KeyWordMapper("msg_id"))
  );

  private String getBuyerId(JsonObject message) {
    final JsonObject from = message.getJsonObject("from");
    final String fromRole = from.getString("role", "");

    final String uid;
    if ("user".equals(fromRole)) {
      uid = from.getString("uid");
    } else {
      uid = message.getJsonObject("to").getString("uid");
    }
    return uid;
  }

  @Override
  public boolean test(JsonObject jsonObject) {

    final JsonObject body = jsonObject.getJsonObject("body");

    final JsonObject message = body.getJsonObject("message");
    if (message != null) {

      final String sid = body.getString("sid");
      final String aid = body.getString("aid");
      final String uid = getBuyerId(message);

      for (KeyWordMapper mapper : UNIQUE_KEY_MAPPERS.get()) {
        final String key = mapper.apply(message);
        if (key != null) {
          final String uniqueKey = String.join(".", sid, aid, uid, key);
          final Boolean absent = cache.get().asMap().putIfAbsent(uniqueKey, Boolean.TRUE);
          final boolean accept = absent == null;
          if (!accept) {
            log.info("filter by DuplicateMessage, {} {}", mapper.key, key);
            return false;
          }
        }
      }
    }

    return true;
  }

}
